package com.bjx.flow.util;

import camundafeel.de.odysseus.el.ExpressionFactoryImpl;
import camundafeel.de.odysseus.el.util.SimpleContext;
import camundafeel.javax.el.ExpressionFactory;
import camundafeel.javax.el.ValueExpression;
import com.alibaba.cloud.commons.lang.StringUtils;
import org.camunda.bpm.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.camunda.bpm.engine.impl.el.ExpressionManager;
import org.camunda.bpm.engine.impl.pvm.PvmActivity;
import org.camunda.bpm.engine.impl.pvm.PvmTransition;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.impl.task.TaskDefinition;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @desc: 节点解析
 * @author: liushuai
 * @date: 2023/1/5 10:36
 */
public class TaskNodeUtil {
    public static final String USER_TASK = "userTask";
    public static final String END_EVENT = "EndEvent";
    public static final String MULTI_INSTANCE_BODY = "multiInstanceBody";
    public static final String EXCLUSIVE_GATEWAY = "exclusiveGateway";
    public static final String INCLUSIVE_GATEWAY = "inclusiveGateway";
    public static final String PARALLEL_GATEWAY = "parallelGateway";

    public static void endEvent(List<TaskDefinition> taskDefinitions, ActivityImpl activityImpl) {
        TaskDefinition taskDefinition = new TaskDefinition(null);
        ExpressionManager expressionManager = new ExpressionManager();
        taskDefinition.setKey(activityImpl.getId() == null ? "end" : activityImpl.getId());
        String name = activityImpl.getProperty("name") == null ? "结束" : activityImpl.getProperty("name").toString();
        taskDefinition.setNameExpression(expressionManager.createExpression(name));
        taskDefinitions.add(taskDefinition);
    }

    public static void userTask(List<TaskDefinition> taskDefinitions, ActivityImpl activityImpl) {
        TaskDefinition taskDefinition = ((UserTaskActivityBehavior) activityImpl.getActivityBehavior())
                .getTaskDefinition();
        taskDefinitions.add(taskDefinition);
    }

    public static void multiInstanceBody(List<TaskDefinition> taskDefinitions, ActivityImpl activityImpl) {
        List<ActivityImpl> list = ((ActivityImpl) activityImpl).getActivities();
        for (ActivityImpl act : list) {
            TaskDefinition taskDefinition = ((UserTaskActivityBehavior) act.getActivityBehavior())
                    .getTaskDefinition();
            taskDefinitions.add(taskDefinition);
        }

    }

    public static void exclusiveGateway(List<TaskDefinition> taskDefinitions, ActivityImpl activityImpl, String activityId, String processInstanceId, Map<String, Object> condition,String type) {
        List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
        String defaultTransition = (String) activityImpl.getProperty("default");
        if (outTransitions.size() == 1) {
            taskDefinitions.addAll(nextTaskDefinitions((ActivityImpl) outTransitions.get(0).getDestination(),
                    activityId, processInstanceId, condition));
        } else if (outTransitions.size() > 1) {
            // 如果排他网关有多条线路信息
            List<TaskDefinition> definitions = new ArrayList<>();
            for (PvmTransition tr1 : outTransitions) {
                ActivityImpl actImpl = (ActivityImpl) tr1.getDestination();

                // 获取排他网关线路判断条件信息
                Object s = tr1.getProperty("conditionText");
                if (null == s) {
                    //排他网关并且
                    if(EXCLUSIVE_GATEWAY.equals(type) && definitions.size() == 0){
                        definitions.addAll(nextTaskDefinitions((ActivityImpl) tr1.getDestination(), activityId,
                                processInstanceId, condition));
                    }
                    continue;
                }
                if (actImpl.getProperty("type").toString().contains(END_EVENT)) {
                    endEvent(definitions, actImpl);
                    break;
                }
                // 判断el表达式是否成立
                if (isCondition(condition, StringUtils.trim(s.toString()))) {
                    List<TaskDefinition> defs = nextTaskDefinitions((ActivityImpl) tr1.getDestination(), activityId,
                            processInstanceId, condition);
                    if(EXCLUSIVE_GATEWAY.equals(type) && definitions.size() > 0){
                        definitions = defs;
                    }else{
                        definitions.addAll(defs);
                    }

                }
            }
            taskDefinitions.addAll(definitions);
            if (taskDefinitions.size() == 0 && StringUtils.isNotBlank(defaultTransition)) {
                for (PvmTransition tr3 : outTransitions) {
                    if (defaultTransition.equals(tr3.getId())) {
                        ActivityImpl actImpl = (ActivityImpl) tr3.getDestination();
                        if (actImpl.getProperty("type").toString().contains(END_EVENT)) {
                            endEvent(taskDefinitions,actImpl);
                            break;
                        }
                        taskDefinitions.addAll(nextTaskDefinitions(actImpl,
                                activityId, processInstanceId, condition));
                    }
                }
            }
        }
    }

    public static void  parrallelGateway(List<TaskDefinition> taskDefinitions, ActivityImpl activityImpl, String activityId, String processInstanceId, Map<String, Object> condition){
        List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
        for (PvmTransition tr1 : outTransitions) {
            taskDefinitions.addAll(nextTaskDefinitions((ActivityImpl) tr1.getDestination(), activityId,
                    processInstanceId, condition));
        }

    }

    /**
     * 获取下一个任务节点信息
     *
     * @param activityImpl
     * @param activityId
     * @param processInstanceId
     * @param condition
     * @return: java.util.List<org.camunda.bpm.engine.impl.task.TaskDefinition>
     * @Author: liushuai
     * @Date: 2023/1/4 16:28
     */
    public static List<TaskDefinition> nextTaskDefinitions(ActivityImpl activityImpl, String activityId, String processInstanceId, Map<String, Object> condition) {
        PvmActivity ac = null;
        Object s = null;
        List<TaskDefinition> taskDefinitions = new CopyOnWriteArrayList<TaskDefinition>();
        //流程节点类型
        String type = (String) activityImpl.getProperty("type");
        //流程节点id
        String id = activityImpl.getId();
        // 如果遍历节点为用户任务并且节点不是当前节点信息
        if (USER_TASK.equals(type) && !activityId.equals(id)) {
            // 获取该节点下一个节点信息
            userTask(taskDefinitions, activityImpl);
        } else if (type.contains(END_EVENT) && !activityId.equals(id)) {
            // 设置结束节点
            endEvent(taskDefinitions, activityImpl);
        } else if (MULTI_INSTANCE_BODY.equals(type) && !activityId.equals(id)) {
            // 获取该节点下一个节点信息
            multiInstanceBody(taskDefinitions, activityImpl);
        } else if (EXCLUSIVE_GATEWAY.equals(type)
                || INCLUSIVE_GATEWAY.equals(type)) {
            // 当前节点为exclusiveGateway或inclusiveGateway
            exclusiveGateway(taskDefinitions, activityImpl, activityId, processInstanceId, condition,type);
        } else if (PARALLEL_GATEWAY.equals(type)) {
            parrallelGateway(taskDefinitions,activityImpl,activityId,processInstanceId,condition);
        } else {
            // 获取节点所有流向线路信息
            List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
            List<PvmTransition> outTransitionsTemp = null;
            for (PvmTransition tr : outTransitions) {
                // 获取线路的终点节点
                ac = tr.getDestination();
                type = (String) ac.getProperty("type");
                // 如果流向线路为排他网关或包容网关
                if (EXCLUSIVE_GATEWAY.equals(type)
                        || INCLUSIVE_GATEWAY.equals(type)) {
                    exclusiveGateway(taskDefinitions, (ActivityImpl) ac, activityId, processInstanceId, condition,type);
                } else if (USER_TASK.equals(type)) {
                    userTask(taskDefinitions,(ActivityImpl) ac);
                } else if (MULTI_INSTANCE_BODY.equals(type)) {
                    multiInstanceBody(taskDefinitions,(ActivityImpl) ac);
                } else if (type.contains(END_EVENT)) {
                    // 设置结束节点
                    endEvent(taskDefinitions,(ActivityImpl) ac);
                } else if (PARALLEL_GATEWAY.equals(type)) {
                    parrallelGateway(taskDefinitions,(ActivityImpl) ac,activityId,processInstanceId,condition);
                }
            }
        }
        return taskDefinitions;
    }

    public static boolean isCondition(Map<String, Object> condition, String el) {
        ExpressionFactory factory = new ExpressionFactoryImpl();
        SimpleContext context = new SimpleContext();
        if (condition != null) {
            Iterator<Map.Entry<String, Object>> iterator = condition.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> value = iterator.next();
                context.setVariable(value.getKey(), factory.createValueExpression(value.getValue(), String.class));
            }
        }
        ValueExpression e = factory.createValueExpression(context, el, boolean.class);
        return (Boolean) e.getValue(context);
    }
}
